﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Threading;
using System.Xml;
using PTAPI.Core.Domain;

namespace PTAPI.Core
{

    public class RequestState
    {
        const int BUFFER_SIZE = 1024;
        public StringBuilder requestData;
        public byte[] BufferRead;
        public HttpWebRequest request;
        public HttpWebResponse response;
        public Stream streamResponse;
        public RequestState()
        {
            BufferRead = new byte[BUFFER_SIZE];
            requestData = new StringBuilder("");
            request = null;
            streamResponse = null;
        }
    }

    public class HTTPService
    {
        static Action<object> CallbackMethod;
        Token currentToken;

        public static ManualResetEvent allDone = new ManualResetEvent(false);
        const int BUFFER_SIZE = 1024;
        const int DefaultTimeout = 2 * 60 * 1000; // 2 minutes timeout 

        // Abort the request if the timer fires. 
        private static void TimeoutCallback(object state, bool timedOut)
        {
            if (timedOut)
            {
                HttpWebRequest request = state as HttpWebRequest;
                if (request != null)
                {
                    request.Abort();
                }
            }
        }

        public void Authorize(string requestString, Action<object> callbackMethod, string name, string pass)
        {
            CallbackMethod = callbackMethod;
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestString);
            request.Credentials = new NetworkCredential(name, pass);
            RequestState requestState = new RequestState();
            requestState.request = request;

            IAsyncResult result = (IAsyncResult)request.BeginGetResponse(new AsyncCallback(ResponseCallback), requestState);
            ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), request, DefaultTimeout, true);
            allDone.WaitOne();
            requestState.response.Close();
        }

        public void SendRequest(string requestString, Action<object> callbackMethod)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestString);
            RequestState requestState = new RequestState();
            requestState.request = request;

            IAsyncResult result = (IAsyncResult)request.BeginGetResponse(new AsyncCallback(ResponseCallback), requestState);
            ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), request, DefaultTimeout, true);
            allDone.WaitOne();
            requestState.response.Close();
        }

        private static void ResponseCallback(IAsyncResult asynchronousResult)
        {
            RequestState requestState = (RequestState)asynchronousResult.AsyncState;
            HttpWebRequest request = requestState.request;
            requestState.response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
            Stream responseStream = requestState.response.GetResponseStream();
            requestState.streamResponse = responseStream;
            IAsyncResult asynchronousInputRead = responseStream.BeginRead(requestState.BufferRead, 0, BUFFER_SIZE, new AsyncCallback(ReadCallBack),requestState);
            return;
        }

        private static void ReadCallBack(IAsyncResult asyncResult)
        {
            RequestState requestState = (RequestState)asyncResult.AsyncState;
            Stream responseStream = requestState.streamResponse;
            int read = responseStream.EndRead(asyncResult);
            
            StreamReader objReader = new StreamReader(responseStream);

            XmlDocument xmlDoc = new XmlDocument();

            xmlDoc.Load(objReader);
            if (CallbackMethod != null)
            {
                CallbackMethod(responseStream);
            }
        }

    }
}
